import java.util.ArrayList;
import java.net.*;
import java.io.*;
import java.lang.Math;
public class Match implements Runnable
{

	Player[] player;
	int numPlayers;
	boolean fighting;

	public Match() throws IOException
	{
		fighting = false;
		numPlayers = 0;
		player = new Player[2];
		Thread mthread = new Thread(this);
		mthread.start();
		System.out.println("Match created");
	}

	public void run()
	{
		try
		{
			System.out.println("Match running");

			while(numPlayers < 1){Thread.sleep(500);}


			player[0].loadName();
			player[0].sendMessage("Waiting for second player...");
			player[0].sendMessage(player[0].stats());

			while(numPlayers < 2){Thread.sleep(500);}

			player[1].loadName();
			player[1].sendMessage(player[1].stats());

			sendAllPlayersAMessage("Second player connected.\n"+player[0].name+" Vs. "+player[1].name);

			for(int x = 0; x < 3; x++)
			{
				sendAllPlayersAMessage(".");
				rundown(500000000); //0.5 seconds

			}

			sendAllPlayersAMessage("FIGHT!!!");
			fighting = true;

			player[0].start();
			player[1].start();

			while(fighting)
			{
				if(player[0].madeMove) //player 0 attacks player 1
				{
					player[0].canMove = false;

					player[0].madeMove = false;
					player[1].madeMove = false;

					System.out.println(player[0].name +" attacked "+ player[1].name);

					attack(player[0], player[1], 1000000000,"You Attack " + player[1].name + " with your stick!", player[0].name + " attacks with a stick!");

					sendHP();
				}

				if(player[1].madeMove) //player 1 attacks player 0
				{
					player[1].canMove = false;

					player[0].madeMove = false;
					player[1].madeMove = false;

					System.out.println(player[1].name +" attacked "+ player[0].name);

					attack(player[1], player[0], 1000000000,"You Attack "+player[0].name+" with your stick!",player[1].name + " attacks with a stick!");

					sendHP();
				}

				player[0].canMove = true;
				player[1].canMove = true;

				if (player[0].hp <= 0)
				{
					sendAllPlayersAMessage(player[1].name + " wins!!!");
					fighting = false;
				}
				else if (player[1].hp <= 0)
				{
					sendAllPlayersAMessage(player[0].name + " wins!!!");
					fighting = false;
				}
			}
		}
		catch(Exception e){}

	}

	//Attacker can not move; Defender can move and is given time to block.*/
	public long attack(Player attacker, Player defender, long timeRemaining, String messageAttacker, String messageDefender) throws IOException
	{
		defender.canMove = true;

		attacker.sendMessage(messageAttacker);
		defender.sendMessage(messageDefender);

		while(timeRemaining > 0)
		{
			if( (timeRemaining = sequesterPlayer(defender, timeRemaining, "Blocked!", "Hit!")) > 0)
			{
				if( (timeRemaining = sequesterPlayer(defender,timeRemaining,(defender.name + " Counter Attacks!"), "")) > 0)
				{
					attacker.hp -= (defender.atk - attacker.def) * 2 * (critical(defender, attacker) + 1); //the original attacker is losing health because he got countered

					defender.canMove = false;
					attacker.canMove = true;

					timeRemaining = attack(defender, attacker, timeRemaining, "", "");
				}
			}
			else
			{
				defender.hp -= (attacker.atk - defender.def) * (critical(attacker, defender) + 1); //original defender loses health because he got hit

			}
		}
		return timeRemaining;
	}

	public void rundown(long dur)
	{
		long initialTime = System.nanoTime();
		long dif=0;
		while( dif < dur )
		{
			dif = (System.nanoTime()-initialTime);
			System.out.println(dif);
		}
	}

	/*Player p is given dur time to react
	if they do, succeed is sent to all players if not fail is sent instead*/
	//dur is for duration
	public long sequesterPlayer(Player p, long dur, String succeed, String fail) throws IOException
	{
		long initialTime = System.nanoTime();
		long dif = 0;

		while(dif < dur)
		{
			System.out.print("");
			dif = (System.nanoTime()-initialTime);

			if(p.madeMove)
			{
				p.madeMove = false;
				sendAllPlayersAMessage(succeed);
				return (dur-dif);
			}
		}
		sendAllPlayersAMessage(fail);
		return 0;
	}

	public void sendAllPlayersAMessage(String msg) throws IOException
	{
		for( Player p : player )
			p.sendMessage(msg);
	}

	public void addPlayer(Socket in)
	{
		player[numPlayers] = new Player(in);
		numPlayers++;
	}

	public int critical(Player attk, Player defn) throws IOException
	{


		if(attk.hp <= Player.HP_MAX * 0.1)
		{
			int roll = (int)(Math.random() * (Player.ATK_MIN*1.5 - 1 + 1) + 1); // Max 33% chance
			if (roll > attk.atk)
			{
				sendAllPlayersAMessage("CRITICAL HIT");
				return Math.abs((int)(Math.random() * ((defn.hp - attk.hp)/attk.atk) + 1));
			}
		}
		else if(attk.hp <= Player.HP_MAX * 0.3)
		{
				int roll = (int)(Math.random() * (Player.ATK_MIN*1.25 - 1 + 1) + 1); // Max 20% chance
				if (roll > attk.atk)
				{
					sendAllPlayersAMessage("CRITICAL HIT");
					return Math.abs((int)(Math.random() * ((defn.hp - attk.hp)/attk.atk) + 1));
				}
		}
		else if(attk.hp <= Player.HP_MAX * 0.5)
		{
			int roll = (int)(Math.random() * (Player.ATK_MIN*1.11 - 1 + 1) + 1); // Max 10% chance
			if (roll > attk.atk)
			{
				sendAllPlayersAMessage("CRITICAL HIT");
				return Math.abs((int)(Math.random() * ((defn.hp - attk.hp)/attk.atk ) + 1));
			}
		}
		else
		{
			int roll = (int)(Math.random() * (Player.ATK_MIN*1.02 - 1 + 1) + 1); // Max 2% chance
			if (roll > attk.atk)
			{
				sendAllPlayersAMessage("CRITICAL HIT");
				return (int)(Math.random() * ((defn.hp - attk.hp)/attk.atk) + 1);
			}
		}

		return 0;
	}

	public void sendHP() throws IOException
	{
		for(Player p : player)
		{
			if (p.hp < 0)
				p.hp = 0;
		}

		String score;
		for(int i = 0; i < player.length; i++)
		{
			score = "";
			score += "\n";
			score += "Your HP: " + player[i].hp;
			for(int j = 0; j < player.length; j++)
			{
				if(i != j)
					score += "\n" + player[j].name + "'s HP: " + player[j].hp;
			}
			score += "\n";

			player[i].sendMessage(score);
		}

	}

}